﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Snowdreamist.Collection;
using Snowdreamist.Runtime.Services;

namespace Snowdreamist.Runtime
{
    public class ModuleRuntime : Snowdreamist.Runtime.Runtime
    {
        #region static

        public static ModuleRuntime GetRuntime(IModuleDefinition definition)
        {
            if (definition == null)
                throw new ArgumentNullException("definition");

            ModuleRuntime runtime = null;

            if (!_runtimes.TryGetValue(definition.ExportType, out runtime))
            {
                // try to create by system runtime
                lock (_syncRoot)
                {
                    if (!_runtimes.TryGetValue(definition.ExportType, out runtime))
                    {
                        // create
                        runtime = SystemRuntime.Current.CreateModuleRuntime(definition);
                        // add
                        _runtimes.Add(definition.ExportType, runtime);
                    }
                }
            }

            return runtime;
        }

        public static ModuleRuntime GetRuntime<T>()
        {
            ModuleRuntime runtime = null;
            if (!_runtimes.TryGetValue(typeof(T), out runtime))
            {
                // not found
                lock (_syncRoot)
                {
                    if (!_runtimes.TryGetValue(typeof(T), out runtime))
                    {
                        runtime = SystemRuntime.Current.CreateModuleRuntime<T>();
                        // add
                        _runtimes.Add(typeof(T), runtime);
                    }
                }
            }

            return runtime;
        }

        private static readonly object _syncRoot = new object();

        private static readonly ThreadSafeDictionary<Type, ModuleRuntime> _runtimes = new ThreadSafeDictionary<Type, ModuleRuntime>();

        #endregion static

        internal ModuleRuntime(
            IModuleDefinition definition,
            IEnumerable<Tuple<Type, IModuleRuntimeService>> services
            )
            : base(null)
        {
            // init
            if (definition == null)
                throw new ArgumentNullException("definition");
            // init
            this.Definition = definition;
            // check & register services
            if (services != null)
            {
            }
        }

        /// <summary>
        /// Module definiton
        /// </summary>
        public IModuleDefinition Definition { get; private set; }

        #region protected

        protected virtual void Initialize()
        {
            // init all module service
        }

        protected virtual void Destroy()
        {
            // destory all module service
        }

        protected override object FailedToRetrieveService(Type serviceContractType)
        {
            // if cannot find the service in module runtime, try system runtime
            return SystemRuntime.Current.GetService(serviceContractType);
        }

        #endregion protected
    }

    /// <summary>
    /// Only used to get module runtime
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static class ModuleRuntime<T>
    {
        public static ModuleRuntime Current
        {
            get
            {
                return ModuleRuntime.GetRuntime<T>();
            }
        }
    }
}